package sistemioperativi.barbiere.es12;
import java.util.LinkedList;
import java.util.concurrent.locks.*;

public class SaloneLCFiFO extends Salone{

	private Lock l = new ReentrantLock();
	private Condition barbiere = l.newCondition();
	private Condition salaDAttesa = l.newCondition();
	private Condition taglioCapelli = l.newCondition();
	
	private boolean clienteServito = false;
	private boolean prossimoCliente = false;
	
	private LinkedList<Thread> codaClienti = new LinkedList<Thread>();
	
	public SaloneLCFiFO(int capienza) {
		super(capienza);
	}

	@Override
	protected void getCliente() throws InterruptedException {
		
		l.lock();
		try{
			if(numClientiInAttesa == 0){
				barbiereAddormentato = true;
			}
			
			while(numClientiInAttesa == 0){
				barbiere.await();
			}
		
			barbiereAddormentato = false;
			prossimoCliente = true;
			salaDAttesa.signalAll();
			
		}finally{l.unlock();}
		
	}

	@Override
	protected void congedaCliente() throws InterruptedException {
		l.lock();
		
		try{
			clienteServito = true;
			taglioCapelli.signal();
		
		}finally{l.unlock();}
		
	}

	@Override
	protected boolean entra() throws InterruptedException {
		boolean esito = true;
		
		l.lock();
		try {
			if(barbiereAddormentato){
				siediInPoltrona();
			}else
				if(numClientiInAttesa < capienza){
					attendiInSalaDAttesa();
					siediInPoltrona();

				}else{
					esito = false;
				}
		} finally {
			l.unlock();
		}
		
		
		return esito;
	}

	private void siediInPoltrona() throws InterruptedException {
		barbiereAddormentato = false;
		barbiere.signal();
		while(!clienteServito){
			taglioCapelli.await();
		}
		clienteServito = false;	
		
	}

	private void attendiInSalaDAttesa() throws InterruptedException {
		codaClienti.addLast(Thread.currentThread());
		numClientiInAttesa++;
		while(!possoSedereInPoltrona()){
			salaDAttesa.await();
		}
		
		prossimoCliente = false;
		codaClienti.removeFirst();
		numClientiInAttesa--;
		
	}

	private boolean possoSedereInPoltrona() {
		return Thread.currentThread() == codaClienti.peek() && prossimoCliente;
	}
	

}
